package com.sj.purchase.modules.cost.service.stock;

import com.sj.purchase.modules.cost.domain.order.InOrderItem;
import com.sj.purchase.modules.cost.domain.order.OutOrderItem;
import com.sj.purchase.modules.cost.repository.imei.ImeiRepository;
import com.sj.purchase.modules.cost.repository.order.InOrderItemRepository;
import com.sj.purchase.modules.cost.repository.order.OutOrderItemRepository;
import com.sj.purchase.modules.cost.repository.order.SkuAvgPriceRepository;
import com.sj.purchase.modules.cost.repository.stock.SkuStockRepository;
import com.sj.purchase.modules.cost.repository.stock.StockCostRepository;
import com.sj.purchase.modules.cost.domain.stock.StockCost;
import com.sj.purchase.modules.cost.domain.imei.Imei;
import com.sj.purchase.modules.cost.views.VSkuStock;
import com.sj.purchase.util.DateUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by 宋开宗 on 2017/7/21 0021.
 */
@Service
public class StockCostService {
    @Autowired
    private StockCostRepository repository;
    @Autowired
    private SkuStockRepository skuStockRepository;
    @Autowired
    private InOrderItemRepository inOrderItemRepository;
    @Autowired
    private OutOrderItemRepository outOrderItemRepository;
    @Autowired
    private ImeiRepository imeiRepository;
    @Autowired
    private SkuAvgPriceRepository skuAvgPriceRepository;

    private static String FORMAT = "yyyy-MM-dd";
    private static final Logger logger = LoggerFactory.getLogger(StockCostService.class);

    /**
     * 计算当天的库存成本
     *
     * @param day 某一天（yyyy-MM-dd）
     */
    @Transactional
    public void calculateStockCost(Date day) {
        final double[] totalAvgCost = {0};//当日总平均价
        final double[] totalImeiCost = {0};//当日总imei价
        final long[] totalSum = {0};//所有sku总数量
        Map<String, Double> avgPriceMap = new HashMap<>();//sku：平均价
        skuAvgPriceRepository.findByIdDay(day).forEach(s -> avgPriceMap.put(s.getId().getSkuNo(), s.getPrice()));
        //期初库存,按sku分组，当天的每个sku与num，每个sku可能来源与多个订单
        List<VSkuStock> startStocks = skuStockRepository.findBeginStock(day);
        //------------------以下计算期初库存成本，并累计数量
        startStocks.forEach(stock -> {
            String sku = stock.getSku();
            //该sku平均成本价
            Double skuAvgCost = Optional.ofNullable(avgPriceMap.get(sku)).orElse(0D);
            totalSum[0] += stock.getNum();
            totalAvgCost[0] += stock.getNum() * skuAvgCost;
            //计算成本
            //获取期初库存的imei，按订单分组，一个sku可能来源于多个入库单，理论上遍历此集合所有数量之和应==stock.getNum()
            List<Object[]> beginStock = imeiRepository.findStockGroupOrder(sku, DateUtils.getStartOfDay(day));
            //该库存的sku，即使有imei，这里如果其对应的入库单不全，也可能查不到，此时按平均价处理
            if (beginStock.size() != 0) {//有imei号则计算imei成本
                beginStock.forEach(o -> {
                    //拿到当时的成本价
                    Double price = inOrderItemRepository.findCost(DateUtils.getStartOfDay((Date) o[1]), o[0].toString(), sku);
                    //此代码只有在系统刚运行一段时间内会出现为null的情况，此后理论上都应该会查到入库单及价格。
                    if (Objects.isNull(price))
                        logger.error("查不到期初库存订单号为：" + o[0].toString() + "的入库单");
                    //*数量
                    double orderPrice = Integer.valueOf(o[2].toString()) * Optional.ofNullable(price).orElse(skuAvgCost);
                    totalImeiCost[0] += +orderPrice;
                });
            } else
                totalImeiCost[0] += stock.getNum() * skuAvgCost;//无imei按平均成本价
        });

        //------------------以下计算当天入库成本，并累计数量
        //获取当天入库的所有orderItem
//        List<InOrderItem> inOrderItems = inOrderItemRepository.findByOrderIdSaveDateDay(day);
        List<InOrderItem> inOrderItems = null;
        inOrderItems.forEach(item -> {
            //判断该sku是否有imei
            List<Imei> inImeis = imeiRepository.findBySkuDay(item.getSkuNo(), DateFormatUtils.format(day, FORMAT), Imei.ImeiType.IN.toString());
            //该sku平均成本价
            Double skuAvgCost = Optional.ofNullable(avgPriceMap.get(item.getSkuNo())).orElse(0D);
            totalSum[0] += item.getNum();//累计入库数量
            totalAvgCost[0] += item.getNum() * skuAvgCost;//计算平均成本
            //计算imei成本
            if (inImeis.size() != 0) {
                totalImeiCost[0] += item.getPrice() * item.getNum();
            } else {
                totalImeiCost[0] += skuAvgCost * item.getNum();
            }
        });
        //------------------以下计算当天出库成本，并累计数量
//        List<OutOrderItem> outOrderItems = outOrderItemRepository.findByOrderIdSaveDateDay(day);
        //获取当天出库的sku
        List<OutOrderItem> outOrderItems = null;
        outOrderItems.forEach(item -> {
            List<Imei> outImeis = imeiRepository.findBySkuDay(item.getSkuNo(), DateFormatUtils.format(day, FORMAT), Imei.ImeiType.OUT.toString());
            Double skuAvgCost = Optional.ofNullable(avgPriceMap.get(item.getSkuNo())).orElse(0D);//该sku平均成本价
            totalSum[0] -= item.getNum();//累计出库数量
            totalAvgCost[0] -= item.getNum() * skuAvgCost;//计算平均成本
            //计算imei成本
            if (outImeis.size() != 0) {
                outImeis.forEach(imei -> {
                    //获取该出库单对应的入库单
                    Imei inImei = imeiRepository.findDistinctFirstByIdImeiAndSkuAndImeiType(imei.getId().getImei(), imei.getSku(), Imei.ImeiType.IN);
                    if (Objects.isNull(inImei)) {
                        logger.error("查不到出库IMEI" + imei.getId().getImei() + "对应的入库单记录,按平均价计算");
                        totalImeiCost[0] -= skuAvgCost;
                    } else {
                        double outCost = inOrderItemRepository.findCost(inImei.getId().getOrderNo(), inImei.getSku());
                        totalImeiCost[0] -= outCost;
                    }
                });
            } else {
                totalImeiCost[0] -= skuAvgCost * item.getNum();
            }
        });

        StockCost stockCost = new StockCost();
        stockCost.setCreateDate(day).setNum(totalSum[0]).setAvgCost(totalAvgCost[0]).setImeiCost(totalImeiCost[0]);
        repository.save(stockCost);
    }
}
